#include <iostream>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <cstring>
using namespace std;
/*
有名管道：有名字的管道，会在文件系统中创建一个管道文件但数据传输还是在内核空间的内存缓冲区发生
        可用于不同进程之间通信(非亲缘进程间)

语法：
 #include <sys/types.h>
 #include <sys/stat.h>

 int mkfifo(const char *pathname, mode_t mode);
    功能：创建一个管道文件，并存在与文件系统中
    参数1：管道文件的名称
    参数2：管道文件的权限，内容详见open函数的mode参数
    返回值：成功返回0，失败返回-1并置位错误码

    注意：管道文件被创建后，其他进程就可以进行打开读写操作了
          但是必须要保证当前管道文件的两端都打开后，才能进行读写操作，否则函数会在open处阻塞

虽然支持多个读写进程的打开和访问​​，但会面临数据竞争问题，所以还是双进程，写读两个进程使用最好
*/
// 进程1
int main1()
{
    // 该文件主要负责创建管道文件，注意：如果管道文件已经存在，则mkfifo函数会报错
    if (mkfifo("myfifo", 0664) == -1) // mkfifo也会增加管道文件的引用计数
    {
        perror("mkfifo error");
        return -1;
    }
    cout << "管道文件创建成功" << endl;

    // unlink函数：文件系统路径立即消失(非阻塞)，管道文件引用计数减1
    // unlink("myfifo");
    /*
    1.如果unlink先执行，但是还有进程还有新进程打开了管道文件
      那么进程会被阻塞在open函数处，但已经打开的进程不影响继续使用
    2.当其他进程中的文件描述符都关闭，并执行了unlink
      管道文件引用数位0，管道文件会被立即删除
    3.如果其他进程文件描述符都关闭了，但没有执行unlink，那么管道文件会一直存在
      直到系统重启后消失或者手动删除
*/
}

// 进程2  发送消息
int main2()
{
    // 打开管道文件
    int sfd = -1;
    if ((sfd = open("./myfifo", O_WRONLY)) == -1) // 等待读端打开，否则阻塞
    {
        perror("open error");
        return -1;
    }
    // 准备要写入的数据
    char wbuf[128] = "";
    while (1)
    {
        printf("请输入>>>");
        fgets(wbuf, sizeof(wbuf), stdin); // 从终端输入数据
        wbuf[strlen(wbuf) - 1] = 0;       // 将换行换成'\0'
        // 将数据写入管道
        write(sfd, wbuf, strlen(wbuf));
        if (strcmp(wbuf, "quit") == 0)
            ;
        break;
    }
    // 关闭文件
    close(sfd);
    return 0;
}

// 进程3  接收消息
int mian3()
{
    // 打开管道文件
    int rfd = -1;
    if ((rfd = open("./myfifo", O_RDONLY)) == -1)
    {
        perror("open error");
        return -1;
    }
    // 准备要写入的数据
    char rbuf[128] = "";
    while (1)
    {
        // 将容器清空
        bzero(rbuf, sizeof(rbuf));
        // 从管道文件中读取数据
        read(rfd, rbuf, sizeof(rbuf));
        printf("收到数据为：%s\n", rbuf);
        if (strcmp(rbuf, "quit") == 0)
        {
            break;
        }
    }
    // 关闭文件
    close(rfd);
    return 0;
}